/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */


import hilog from '@ohos.hilog';
import worker from '@ohos.worker';
import { ThreadType , MessageQueueThreadSpec} from './MessageQueueThreadSpec';

import { MessageQueueThreadHandler } from './MessageQueueThreadHandler';
import { Looper } from './Looper';
import { MessageQueueThread } from './MessageQueueThread';
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//package com.facebook.react.bridge.queue;

//import android.os.Looper;
//import android.os.Process;
//import android.os.SystemClock;
//import android.util.Pair;
//import com.facebook.common.logging.FLog;
//import com.facebook.proguard.annotations.DoNotStrip;
//import com.facebook.react.bridge.AssertionException;
//import com.facebook.react.bridge.SoftAssertions;
//import com.facebook.react.bridge.UiThreadUtil;
//import com.facebook.react.common.ReactConstants;
//import com.facebook.react.common.futures.SimpleSettableFuture;
//import java.util.concurrent.Callable;
//import java.util.concurrent.Future;

/** Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables. */
//@DoNotStrip
export class MessageQueueThreadImpl implements MessageQueueThread {

    private static readonly Tag = "React MessageQueueThreadImpl"
    private readonly mName: string;
//  private readonly mLooper: Looper;
//  private readonly mHandler: MessageQueueThreadHandler;
//  private readonly mAssertionErrorMessage: string
////  private MessageQueueThreadPerfStats mPerfStats;
    private mIsFinished = false;
    private readonly mWorker: worker.ThreadWorker


//  private constructor(
//      name: string, looper: Looper, /*exceptionHandler: QueueThreadExceptionHandler*/) {
//    this(name, looper, exceptionHandler, null);
//  }

  private constructor(
      name: string, path?: string
      //, looper: Looper,
      /*QueueThreadExceptionHandler exceptionHandler,
      MessageQueueThreadPerfStats stats*/) {
      this.mName = name;
//    this.mWorker = worker;
//    this.mLooper = looper;
//    this.mHandler = new MessageQueueThreadHandler(looper/* exceptionHandler*/);
//    this.mPerfStats = stats;
//    this.mAssertionErrorMessage = "Expected to be called from the '" + getName() + "' thread!";

      if (path != null && path != undefined && path != "") {
          hilog.info(0x0000, MessageQueueThreadImpl.Tag, '%{public}s', "constructor ReactThread: " + this.getName());
      //    this.mWorker = new worker.Worker('/worker/JSQueueThread.ts', { name: name});
          this.mWorker = new worker.ThreadWorker('entry/ets/workers/test.ets', { name: name });
          this.mWorker.postMessage({ message: "hello world" });
//          this.mWorker.onmessage = function(e) {
//              hilog.info(0x0000, MessageQueueThreadImpl.Tag, '%{public}s', e.data.message)
//          }
      }
  }

  /**
   * Runs the given Runnable on this Thread. It will be submitted to the end of the event queue even
   * if it is being submitted from the same queue Thread.
   */
//  @DoNotStrip
//  @Override
//  public boolean runOnQueue(Runnable runnable) {
//    if (mIsFinished) {
//      FLog.w(
//          ReactConstants.TAG,
//          "Tried to enqueue runnable on already finished thread: '"
//              + getName()
//              + "... dropping Runnable.");
//      return false;
//    }
//    mHandler.post(runnable);
//    return true;
//  }
//
//  @DoNotStrip
//  @Override
//  public <T> Future<T> callOnQueue(final Callable<T> callable) {
//    final SimpleSettableFuture<T> future = new SimpleSettableFuture<>();
//    runOnQueue(
//        new Runnable() {
//          @Override
//          public void run() {
//            try {
//              future.set(callable.call());
//            } catch (Exception e) {
//              future.setException(e);
//            }
//          }
//        });
//    return future;
//  }

  /**
   * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
   */
//  @DoNotStrip
//  @Override
//  public boolean isOnThread() {
//    return mLooper.getThread() == Thread.currentThread();
//  }
//
//  /**
//   * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an {@link
//   * AssertionError}) if the assertion fails.
//   */
//  @DoNotStrip
//  @Override
//  public void assertIsOnThread() {
//    SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
//  }

  /**
   * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an {@link
   * AssertionError}) if the assertion fails.
   */
//  @DoNotStrip
//  @Override
//  public void assertIsOnThread(String message) {
//    SoftAssertions.assertCondition(
//        isOnThread(),
//        new StringBuilder().append(mAssertionErrorMessage).append(" ").append(message).toString());
//  }

  /**
   * Quits this queue's Looper. If that Looper was running on a different Thread than the current
   * Thread, also waits for the last message being processed to finish and the Thread to die.
   */
//  @DoNotStrip
//  @Override
//  public void quitSynchronous() {
//    mIsFinished = true;
//    mLooper.quit();
//    if (mLooper.getThread() != Thread.currentThread()) {
//      try {
//        mLooper.getThread().join();
//      } catch (InterruptedException e) {
//        throw new RuntimeException("Got interrupted waiting to join thread " + mName);
//      }
//    }
//  }

//  @DoNotStrip
//  @Override
//  public MessageQueueThreadPerfStats getPerfStats() {
//    return mPerfStats;
//  }
//
//  @DoNotStrip
//  @Override
//  public void resetPerfStats() {
//    assignToPerfStats(mPerfStats, -1, -1);
//    runOnQueue(
//        new Runnable() {
//          @Override
//          public void run() {
//            long wallTime = SystemClock.uptimeMillis();
//            long cpuTime = SystemClock.currentThreadTimeMillis();
//            assignToPerfStats(mPerfStats, wallTime, cpuTime);
//          }
//        });
//  }
//
//  private static void assignToPerfStats(MessageQueueThreadPerfStats stats, long wall, long cpu) {
//    stats.wallTime = wall;
//    stats.cpuTime = cpu;
//  }

//  public getLooper(): Looper {
//    return this.mLooper;
//  }

  public getWorker() {
    return this.mWorker;
  }

  public getName(): string {
    return this.mName;
  }

  public static create(
      spec: MessageQueueThreadSpec): MessageQueueThreadImpl | never {
    if (!spec) return null;

    hilog.info(0x0000, MessageQueueThreadImpl.Tag, '%{public}s', "ReactThread create" + spec.getName());

    switch (spec.getThreadType()) {
      case ThreadType.MAIN_UI:
        return this.createForMainThread(spec.getName()); //exceptionHandler
      case ThreadType.NEW_BACKGROUND:
        return this.startNewBackgroundThread(spec.getName(), spec.getPath())//, exceptionHandler);
      default:
        throw new Error("Unknown thread type: " + spec.getThreadType());
    }
  }
//
//  /** @return a MessageQueueThreadImpl corresponding to Android's main UI thread. */
  private static createForMainThread(
      name: string/*, QueueThreadExceptionHandler exceptionHandler*/): MessageQueueThreadImpl {
//    let mainLooper: Looper = Looper.getMainLooper();
    const mqt: MessageQueueThreadImpl =
        new MessageQueueThreadImpl(name, null);

//    if (UiThreadUtil.isOnUiThread()) {
//      Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
//    } else {
//      UiThreadUtil.runOnUiThread(
//          new Runnable() {
//            @Override
//            public void run() {
//              Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
//            }
//          });
//    }
    return mqt;
  }
//
//  /**
//   * Creates and starts a new MessageQueueThreadImpl encapsulating a new Thread with a new Looper
//   * running on it. Give it a name for easier debugging and optionally a suggested stack size. When
//   * this method exits, the new MessageQueueThreadImpl is ready to receive events.
//   */
  private static startNewBackgroundThread(
      name: string, path?: string, /* exceptionHandler: QueueThreadExceptionHandler*/): MessageQueueThreadImpl {
//    final SimpleSettableFuture<Pair<Looper, MessageQueueThreadPerfStats>> dataFuture =
//        new SimpleSettableFuture<>();
//    long startTimeMillis;
//    Thread bgThread =
//        new Thread(
//            null,
//            new Runnable() {
//              @Override
//              public void run() {
//                Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
//                Looper.prepare();
//                MessageQueueThreadPerfStats stats = new MessageQueueThreadPerfStats();
//                long wallTime = SystemClock.uptimeMillis();
//                long cpuTime = SystemClock.currentThreadTimeMillis();
//                assignToPerfStats(stats, wallTime, cpuTime);
//                dataFuture.set(new Pair<>(Looper.myLooper(), stats));
//                Looper.loop();
//              }
//            },
//            "mqt_" + name,
//            stackSize);
//    bgThread.start();

    return new MessageQueueThreadImpl(name, path);
  }
}
